package com.yesep.learn.design.behavioral.interpreter;

import com.yesep.learn.design.behavioral.interpreter.calculator.Context;
import com.yesep.learn.design.behavioral.interpreter.calculator.*;
import com.yesep.learn.design.behavioral.interpreter.sql.*;

/**
 * 解释器模式（Interpreter Pattern）是一种行为型设计模式，它提供了一种方式来解释定义在某种文法中的句子或表达式。
 * 具体来说，解释器模式通过定义一个解释器来解释语言中的表达式，从而实现对语言的解析和执行。以下是对解释器模式的详细解释：
 * <p>
 * 一、定义与概述
 * 解释器模式用于定义一个语言的文法，并构建一个解释器来解释该语言中的句子。
 * 在解释器模式中，语言中的每个符号都被定义为一个类，这样整个程序就被转换成一个具体的对象树（即抽象语法树，AST）。通过遍历这棵树，解释器就可以对表达式进行解析和执行。
 * <p>
 * 二、组成角色
 * 解释器模式主要包含以下几个角色：
 * <p>
 * 抽象表达式（Abstract Expression）：
 * 定义一个接口，用于解释一个特定的文法规则。这个接口一般声明了一个解释方法（如interpret()），用于解释该表达式，并返回一个解释结果。所有的具体表达式都应该实现这个接口。
 * 终结符表达式（Terminal Expression）：
 * 实现了抽象表达式接口，对应于文法中的终结符。终结符是最基本的文法单位，它们不能再进一步分解。
 * 在解释器模式中，终结符表达式通常包含对终结符的具体解释逻辑。
 * 非终结符表达式（Nonterminal Expression）：
 * 同样实现了抽象表达式接口，对应于文法中的非终结符。非终结符是由其他文法单位（终结符或非终结符）组成的表达式。
 * 非终结符表达式通常包含对其他表达式的引用，以及一个解释方法，用于解释其包含的表达式。
 * 环境（Context）（可选）：
 * 通常包含各个解释器需要的数据或者公共的功能，一般用来传递被所有解释器共享的数据。
 * 在某些复杂的解释场景中，解释器可能需要依赖一些上下文信息来正确地解释表达式。
 * 客户端（Client）：
 * 主要任务是将需要分析的句子或者表达式转换成使用解释器对象描述的抽象语法树（AST），然后调用解释器的解释方法，也可以通过环境角色间接访问解释器的解释方法。
 * 三、工作原理
 * 构建抽象语法树（AST）：
 * 客户端将输入的表达式转换为一系列具体的表达式对象（终结符表达式和非终结符表达式），并将它们组合成一个语法树。
 * 解释执行：
 * 客户端调用语法树的根节点的解释方法，开始解释过程。解释器通过遍历语法树，对每个节点（即表达式对象）进行解释，最终得到整个表达式的解释结果。
 * 四、应用场景
 * 解释器模式特别适合需要评估复杂语法或表达式的场景，如：
 * <p>
 * 编译器：用于将源代码编译成目标代码。
 * 公式解析器：用于解析数学公式或科学计算表达式。
 * 查询处理系统：用于解析数据库查询语句。
 * 文本处理系统：用于解析和处理文本文件中的特定格式或语法。
 * 五、优缺点
 * 优点
 * 灵活性：允许轻松扩展语法或规则，因为可以添加新的表达式类来处理不同类型的语法。
 * 可维护性：将语法解析和执行分离，使得代码更具可维护性。
 * 可读性：模拟了实际语法结构，使得代码更容易理解和维护。
 * 缺点
 * 复杂性：可能会引入复杂性，特别是在处理大型语法或规则时。
 * 性能问题：解释每个表达式可能会涉及多次递归调用，可能导致性能问题。
 * 类膨胀：每条规则至少需要定义一个类，当包含的文法规则很多时，类的个数将急剧增加。
 * 综上所述，解释器模式是一种强大的设计模式，它提供了一种灵活且可扩展的方式来解释和评估特定语言的表达式。
 * 然而，它也存在一些缺点，需要根据具体场景和需求进行权衡选择。
 */
public class Main {
    public static void main(String[] args) {
        sqlExpression();

        calculatorExpression();
    }

    //计算器
    private static void calculatorExpression() {
        Context context = new Context();
        context.setVariable("x", 5);
        context.setVariable("y", 10);

        // 使用 CalculatorUtil 类来计算表达式
        String expressionString = "(x + square(y)) * 2";
        double result = CalculatorUtil.calculate(expressionString, context);
        System.out.println("Result: " + result); // 输出: Result: 210
    }

    //SQL 语法解析
    private static void sqlExpression() {
        Client client = new Client("select id, name from student where id = 1");
        String interpretResult = client.getInterpretResult();
        System.out.println(interpretResult);
    }
}
